import json
import tkinter as tk
from tkinter import PhotoImage
from PIL import Image, ImageTk

from rule import ChessGame

# 用于存储图片对象，防止被垃圾回收
piece_images = []

canvas_map = {}

# 摆放残局界面用的棋子保存字典。
canvas_map2 = {}


class GameMange(object):
    game = None

    @classmethod
    def init_game(cls, board_status, player):
        if cls.game is not None:
            print("Game instance exists.")
            return

        # game = ChessGame()
        cls.game = ChessGame({
            "status": board_status,
            "player": player,
            "count": 0,
            "dead_piece": []
        })
        print("init game finish!")

    @classmethod
    def finish_game(cls):
        cls.game = None

    @classmethod
    def get_game(cls):
        return cls.game


def cal_board_pos(x, y):
    cell_width = 269 / 8.0
    cell_height = 302 / 9.0
    # x_pos_range = [10 + i * cell_width for i in range(9)]
    x_pos = None
    y_pos = None
    for i in range(9):
        c = 10 + i * cell_width
        if c-6 <= x <= c+10:
            x_pos = i
            break
    for i in range(10):
        c = 9 + i * cell_height
        if c-8 <= y <= c+8:
            y_pos = i
            break
    # print("x_pos:", x_pos, y_pos)
    if x_pos is None or y_pos is None:
        return
    return x_pos, y_pos

    # for c in x_pos_range:
    #     if x-6 <= x <= c+6:
    #         x_pos =


def move_piece(piece, pos):
    start_x = 45
    start_y = 45
    cell_width = 269 / 8.0
    cell_height = 302 / 9.0
    canvas = [k for k, v in canvas_map.items() if v == piece]
    if canvas:
        canvas[0].place(x=start_x + pos[0]*cell_width, y=start_y + pos[1]*cell_height)

class ClickState(object):
    state = None
    piece = None

    @classmethod
    def state_transfer(cls, widget, piece, click_pos):
        pass
        if cls.state is None and piece != "BOARD":
            cls.state = "select_piece"
            cls.piece = piece
            cls.widget = widget
        elif cls.state == "select_piece" and piece == 'BOARD' and click_pos:
            c = cls.widget
            pos = cal_board_pos(c.winfo_x() - 45 + 10, c.winfo_y() - 45 + 9)
            cur_player = cls.piece[0]
            is_black = cur_player == "B"
            cur_pos = ChessGame.transform_board_coord(pos, is_black)
            target_pos = ChessGame.transform_board_coord(click_pos, is_black)
            print(cls.piece, pos, click_pos, cur_pos, target_pos)
            game = GameMange.get_game()
            move = (cls.piece, cur_pos, target_pos)
            res = game.step_check(move)
            print("move check:", res)
            # move_piece(cls.piece, click_pos)
            if "OK" == res:
                game.change_status_raw(move)
                #  这中间其实还没有处理对将和被将的情况的检查。
                game.switch_player()
                move_piece(cls.piece, click_pos)
                print("move piece.")
            #
            cls.state = None
            cls.piece = None
        elif cls.state == "select_piece" and piece != 'BOARD':
            if cls.piece[0] == piece[0]:   # 点击的是同色的棋子, 更新为新的棋子
                cls.piece = piece
                cls.widget = widget
            else:  # 点击的是不同色的棋子， 检查是否符合走棋规则
                c = cls.widget
                pos = cal_board_pos(c.winfo_x() - 45 + 10, c.winfo_y() - 45 + 9)
                cur_player = cls.piece[0]
                is_black = cur_player == "B"
                cur_pos = ChessGame.transform_board_coord(pos, is_black)

                click_c = widget
                click_pos = cal_board_pos(click_c.winfo_x() - 45 + 10, click_c.winfo_y() - 45 + 9)
                target_pos = ChessGame.transform_board_coord(click_pos, is_black)
                print(cls.piece, pos, piece, click_pos, cur_pos, target_pos)
                game = GameMange.get_game()
                move = (cls.piece, cur_pos, target_pos)
                res = game.step_check(move)
                print("move check:", res)
                if "OK" == res:
                    # 隐藏被吃掉的棋子
                    widget.place_forget()

                    game.change_status_raw(move)
                    #  这中间其实还没有处理对将和被将的情况的检查。
                    game.switch_player()

                    move_piece(cls.piece, click_pos)
                    print("move piece.")
                    # 情况状态
                    cls.piece = None
                    cls.widget = None
                    cls.state = None


def on_click(event):
    piece = canvas_map.get(event.widget)
    print("Canvas区域被点击了！", event, event.widget, piece, event.x, event.y)
    board_click_pos = None
    if "BOARD" == piece:
        print("点击的是棋盘区域。")
        board_click_pos = cal_board_pos(event.x, event.y)
    ClickState.state_transfer(event.widget, piece, board_click_pos)


def on_piece_click(event):
    piece = canvas_map2.get(event.widget)
    print("Canvas区域被点击了！", event, event.widget, piece, event.x, event.y)


def get_resized_image(image_path, ratio):
    image = Image.open(image_path)
    width, height = image.size
    resized_width = int(width * ratio)
    resized_height = int(height * ratio)
    # print("get_resize_image:", image_path, resized_width, resized_height)
    # Resize the image using the nearest-neighbo
    resized_image = image.resize((resized_width, resized_height))
    return ImageTk.PhotoImage(resized_image)


def add_board(root, image_path, x, y):
    """棋盘的原始尺寸是 538x605, 缩小一半就是 269x302 ,
    canvas 指定的尺寸是 290x320, 左右空白地方的尺寸是10.
    垂直方向的空白大概是9 .
    """
    ratio = 0.5
    # 棋盘的框框的尺寸是269x302
    canvas = tk.Canvas(root, height=320, width=290, bg="SystemButtonFace", highlightthickness=0)
    board_img = get_resized_image(image_path, ratio)
    piece_images.append(board_img)
    canvas.create_image(145, 160, image=board_img)
    canvas.place(x=x, y=y)
    canvas.tag_bind("all", "<Button-1>", on_click)
    return canvas


def add_piece(root, image_path, x, y, handler):
    ratio = 0.5
    canvas = tk.Canvas(root, height=30, width=30, bg="SystemButtonFace", highlightthickness=0)
    piece_img = get_resized_image(image_path, ratio)
    piece_images.append(piece_img)
    canvas.create_image(15, 15, image=piece_img)
    canvas.place(x=x, y=y)
    canvas.tag_bind("all", "<Button-1>", handler)
    return canvas


def build_board_status():
    board_status = [[""] * 9 for x in range(10)]
    # 棋子的初始化是， 黑棋在上方， 红棋在下方。 但是 ChessGame 内部的计算是以红棋在上方，黑棋在下方来计算。
    # 这里需要调转一下棋盘。
    reverse_board = True
    for c, p in canvas_map.items():
        if "BOARD" == p:
            continue
        pos = cal_board_pos(c.winfo_x() - 45 + 10, c.winfo_y() - 45 + 9)
        print(c.winfo_x(), c.winfo_y(), p, pos)
        if reverse_board:
            status_x = 9 - pos[1]
            status_y = 8 - pos[0]
        else:
            status_x = pos[1]
            status_y = pos[0]
        board_status[status_x][status_y] = p
    return board_status


def get_init_board_status():
    board_status = [[""] * 9 for x in range(10)]
    # 棋子的初始化是， 黑棋在上方， 红棋在下方。 但是 ChessGame 内部的计算是以红棋在上方，黑棋在下方来计算。
    # 这里需要调转一下棋盘。
    # ChessGame 内部 已调整为红旗在下方， 黑棋在上方。
    reverse_board = False
    for piece in piece_init_pos:
        pos = piece[1:3]
        if reverse_board:
            status_x = 9 - pos[1]
            status_y = 8 - pos[0]
        else:
            status_x = pos[1]
            status_y = pos[0]
        board_status[status_x][status_y] = piece[3]

    return board_status


def on_button_click():
    """调用了 mainloop之后， 各个组件的的位置才能确定。所以GameManage的初始化只能放在这里。 """
    print("按钮被点击了")
    # board_status = build_board_status()
    #
    # print(board_status)
    # game = ChessGame({
    #     "status": board_status,
    #     "player": "R",
    #     "count": 0,
    #     "dead_piece": []
    # })
    # res = game.step_check(("RP1", (2, 3), (2, 4)))
    # print(res)
    # GameMange.init_game(build_board_status(), "R")


def on_button_reset():
    """复位棋局。"""
    print("reset game!")
    reset_piece_pos()
    GameMange.finish_game()

    GameMange.init_game(get_init_board_status(), "R")


def on_button_analysis():
    game = GameMange.get_game()
    status = game.get_bord_status()
    # print(json.dumps(status, indent=2))
    # 在这里分析棋局。
    """ 第一步是分析有意义的走法， 而不是遍历所有可以的走法， 那样做的计算量太大。 
    有意义的走法包括， 可以吃对方子， 可以阻止对方吃子， 可以准备吃对方棋子。 """
    info = game.get_piece_attack()
    print("info:", info.keys)


piece_init_pos = [
    ["./img/棋子-车.png", 0, 0, "BJ1"],
    ["./img/棋子-马.png", 1, 0, "BM1"],
    ["./img/棋子-象.png", 2, 0, "BX1"],
    ["./img/棋子-士.png", 3, 0, "BS1"],
    ["./img/棋子-将.png", 4, 0, "BW"],
    ["./img/棋子-士.png", 5, 0, "BS2"],
    ["./img/棋子-象.png", 6, 0, "BX2"],
    ["./img/棋子-马.png", 7, 0, "BM2"],
    ["./img/棋子-车.png", 8, 0, "BJ2"],
    ["./img/棋子-炮.png", 1, 2, "BP1"],
    ["./img/棋子-炮.png", 7, 2, "BP2"],
    ["./img/棋子-卒.png", 0, 3, "BB1"],
    ["./img/棋子-卒.png", 2, 3, "BB2"],
    ["./img/棋子-卒.png", 4, 3, "BB3"],
    ["./img/棋子-卒.png", 6, 3, "BB4"],
    ["./img/棋子-卒.png", 8, 3, "BB5"],
    ["./img/棋子-红兵.png", 0, 6, "RB5"],
    ["./img/棋子-红兵.png", 2, 6, "RB4"],
    ["./img/棋子-红兵.png", 4, 6, "RB3"],
    ["./img/棋子-红兵.png", 6, 6, "RB2"],
    ["./img/棋子-红兵.png", 8, 6, "RB1"],
    ["./img/棋子-红炮.png", 1, 7, "RP2"],
    ["./img/棋子-红炮.png", 7, 7, "RP1"],
    ["./img/棋子-红车.png", 0, 9, "RJ2"],
    ["./img/棋子-红马.png", 1, 9, "RM2"],
    ["./img/棋子-红相.png", 2, 9, "RX2"],
    ["./img/棋子-红士.png", 3, 9, "RS2"],
    ["./img/棋子-红帅.png", 4, 9, "RW"],
    ["./img/棋子-红士.png", 5, 9, "RS1"],
    ["./img/棋子-红相.png", 6, 9, "RX1"],
    ["./img/棋子-红马.png", 7, 9, "RM1"],
    ["./img/棋子-红车.png", 8, 9, "RJ1"],
]


def reset_piece_pos():
    start_x = 45
    start_y = 45

    cell_width = 33
    cell_height = 33

    canvas_map_reverse = {v: k for k, v in canvas_map.items()}

    for piece in piece_init_pos:
        canvas = canvas_map_reverse.get(piece[3])
        canvas.place(x=start_x + piece[1] * cell_width, y=start_y + piece[2] * cell_height)
        # canvas = add_piece(root, piece[0], start_x + piece[1] * cell_width, start_y + piece[2] * cell_height)
        # canvas_map[canvas] = piece[3]



def main():
    root = tk.Tk()    # 创建主窗口
    root.title("显示图片示例")
    root.geometry("600x600+100+100")
    root.configure(bg="lightblue")
    # board_img = PhotoImage(file="./img/象棋棋盘3.png")  # 替换为你的图片路径
    # board_img = get_resized_image(c, 0.5)
    # # photo = PhotoImage(file="./img/棋子-象.png")
    # # label = tk.Label(root, image=photo)
    # # label.pack()
    # label = tk.Label(root, image=board_img)
    # label.place(x=50, y=50)
    board_canvas = add_board(root, "./img/象棋棋盘3.png", 50, 50)
    canvas_map[board_canvas] = "BOARD"
    #
    start_x = 45
    start_y = 45

    cell_width = 33
    cell_height = 33
    for piece in piece_init_pos:
        canvas = add_piece(root, piece[0],
                           start_x + piece[1] * cell_width,
                           start_y + piece[2] * cell_height, on_click)
        canvas_map[canvas] = piece[3]
        # 初始化时隐藏棋子。
        canvas.place_forget()

    # 初始化GameManage
    # GameMange.init_game(build_board_status(), "R")
    # 创建几个按钮
    button = tk.Button(root, text="开始棋局", command=on_button_click)
    button.place(x=50, y=10)

    button = tk.Button(root, text="复位棋局", command=on_button_reset)
    button.place(x=120, y=10)

    button = tk.Button(root, text="分析棋局", command=on_button_analysis)
    button.place(x=190, y=10)

    button = tk.Button(root, text="打开新窗口", command=lambda: on_button_new_window(root))
    button.place(x=260, y=10)

    # add_piece(root, "./img/棋子-车.png", start_x, start_y) 
    # add_piece(root, "./img/棋子-象.png", 150, 150)
    root.mainloop()


if __name__ == "__main__":
    main()
